package com.dabai.iot.mqtt.util;

import com.dabai.iot.common.model.DeviceInfo;
import com.dabai.iot.common.model.IotMqttMessage;
import com.dabai.iot.core.api.RemoteMessageHandlerService;
import com.dabai.iot.mqtt.model.MqttMessageContext;
import io.netty.handler.codec.mqtt.MqttQoS;
import io.vertx.core.buffer.Buffer;
import io.vertx.mqtt.MqttEndpoint;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

import java.util.Date;

@Slf4j
@Component
@RequiredArgsConstructor
public class MqttMessageUtil {

    @DubboReference
    private final RemoteMessageHandlerService remoteMessageHandlerService;

    /**
     * 发布消息到设备
     */
    public void sendMessageToDevice(MqttMessageContext mqttMessageContext) {

        MqttEndpoint mqttEndpoint = mqttMessageContext.getMqttEndpoint();
        String traceId = mqttMessageContext.getTraceId();
        String topic = mqttMessageContext.getTopic();
        String payload = mqttMessageContext.getPayload();
        MqttQoS qosLevel = mqttMessageContext.getQosLevel();

        mqttEndpoint.publish(topic, Buffer.buffer(payload), qosLevel, false, false);

        log.info("MQTT Server ====> 发送消息到设备: traceId={} clientId={} topic={} payload: {}", traceId, mqttEndpoint.clientIdentifier(), topic, payload);

        // QoS级别是0时，服务端不会收到任何客户端的响应
        // QoS级别是1时，服务端需要去处理来自客户端的 PUBACK 消息
        // QoS级别是2时，服务端需要去处理来自客户端的 PUBREC 消息
        mqttEndpoint.publishAcknowledgeHandler(messageId -> {
            log.info("MQTT Server ====> Received ack for message1 = {}", messageId);

        }).publishReceivedHandler(messageId -> {
            log.info("MQTT Server ====> Received ack for message2 = {}", messageId);
            // 在该Handler内，端点可以使用 publishRelease 方法响应 PUBREL 消息给客户端
            mqttEndpoint.publishRelease(messageId);

        }).publishCompletionHandler(messageId -> {
            log.info("MQTT Server ====> Received ack for message3 = {}", messageId);
        });
    }

    /**
     * 发布消息到服务端，QoS级别采用 MqttQoS.AT_LEAST_ONCE
     * <p>
     * QoS级别是0时，服务端不会收到任何客户端的响应
     * QoS级别是1时，服务端需要去处理来自客户端的 PUBACK 消息
     * QoS级别是2时，服务端需要去处理来自客户端的 PUBREC 消息
     */
    public void sendMessageToServer(MqttMessageContext mqttMessageContext) {
        String traceId = mqttMessageContext.getTraceId();
        String tenantId = mqttMessageContext.getTenantId();
        MqttEndpoint mqttEndpoint = mqttMessageContext.getMqttEndpoint();
        String clientId = mqttEndpoint.clientIdentifier();
        Pair<String, String> pair = ClientUtil.getProductKeyAndDeviceSn(clientId);
        String productKey = pair.getLeft();
        String deviceSn = pair.getRight();
        String topic = mqttMessageContext.getTopic();
        String payload = mqttMessageContext.getPayload();
        MqttQoS qosLevel = mqttMessageContext.getQosLevel();

        mqttEndpoint.publish(topic, Buffer.buffer(payload), MqttQoS.AT_LEAST_ONCE, false, false);

        log.info("MQTT Server ====> 发送消息到服务端: traceId={} clientId={} topic={} payload: {}", traceId, clientId, topic, payload);

        mqttEndpoint.publishAcknowledgeHandler(msgId -> {
            log.info("MQTT Server ====> Received ack for traceId = {}", traceId);
            DeviceInfo deviceInfo = new DeviceInfo(tenantId, null, productKey, null, deviceSn, null);
            IotMqttMessage mqttMessage = new IotMqttMessage(traceId, topic, payload, qosLevel.value(), null, new Date());
            remoteMessageHandlerService.serverAckMessageHandler(deviceInfo, mqttMessage);
        });
    }

}
